Conversation
// With guard: clean and safe
fun processUser(name: String?, age: Int?): User? {
guard let n = name else { return nil }
guard let a = age else { return nil }
return User(name: n, age: a)
}I like it in general but syntax feels strange to me. But probably it is just me edit: also piqued my interest |
|
I like it, but the guard keyword sounds just a bit off... How about syntax like this: if not let a = input.a { return nil;}
// the reasoning is maybe we would want something like this:
if let b = input.b && let c = input.c { //... }
// and then this:
if not let d = input.d && let e = input.e { //... }
|
|
I don't think we should try to come up with new syntax just for the sake of it, especially if there is already an established one we can borrow. The Swift evolution's commonly rejected proposals has a section regarding |
|
I see three equivalent styles here for handling optionals:
fun processUser(name: String?, age: Int?): User? {
if let n = name {
if let a = age {
return User(name: n, age: a)
}
}
return nil
}
fun processUser(name: String?, age: Int?): User? {
if name == nil || age == nil {
return nil
}
return User(
name: name!,
age: age!
)
}
fun processUser(name: String?, age: Int?): User? {
guard let n = name else { return nil }
guard let a = age else { return nil }
return User(name: n, age: a)
}
From my understanding, all three forms are semantically equivalent and compile down to the same short-circuiting logic. Question: |
Because that's the very feature of it: The else branch is the unhappy case and diverges, and must exit, so that the main branch can always assume that the condition held.
No, it does not have any performance/compilation advantages, its primary benefit is readability and safety. |
|
Some additional context: We already have a form of Another related language is Kotlin, which has the "elvis" operator |
jordanschalm
left a comment
There was a problem hiding this comment.
Thanks for writing this up. I think this feature would be helpful for managing optionals in larger functions.
@turbolent so this will be some kind of pre-condition but also will not fail ? better examples can be constructed with failable cast or optional returning functions I guess. guard let vault <- r as? @{FungibleToken.Vault} else {
return nil
}
vault.withdraw(....)guard let flowVaultReference = acc.storage.borrow<&Flowtoken.Vault>(from:/storage/flowTokenVault>() else {
return nil
}I think this is a bit shift in how we write Cadence also. ( in my opinion little conflicting with pre-conditions ) Like functions should return optionals instead of failing. Also there are cases like this: var listed = false
if let marketV3CollectionRef = acct.capabilities.borrow<&TopShotMarketV3.SaleCollection>(/public/topshotSalev3Collection) {
let salePrice = marketV3CollectionRef.getPrice(tokenID: UInt64(5188888))
if salePrice != nil {
listed = true
}
} else if let marketV1CollectionRef = acct.capabilities.borrow<&Market.SaleCollection>(/public/topshotSaleCollection) {
let salePrice = marketV1CollectionRef.getPrice(tokenID: UInt64(5188888))
if salePrice != nil {
listed = true
}
}
if listed {
panic("moment is already listed for sale")
}
which I think guard will not solve. |
Like a pre-condition the condition must succeed, but unlike the pre-condition execution will not necessarily abort execution: the else branch may panic, which would be equivalent, but it may also just return from the function.
That's a good example! 👍
This proposal and feature do not intend to move developers away from pre-conditions or if they should write code that gracefully returns instead of aborting execution. In many cases pre-conditions are a better choice over But in cases where a pre-condition won't be possible, a guard can help, e.g. for unwrapping optionals (and then panicing or returning from the function, to be decided by the developer). The proposal does try to recommend the early return pattern, and proposes a feature that allows expressing it elegantly.
Yeah, in this example a |
|
btw to make it clear, I like this feature (As people know me know well, I am big hater off forced unwrap operator ); now while reading my comments, it seems a bit negative, it is my general personality, always trying to find an edge case. |
SupunS
left a comment
There was a problem hiding this comment.
Excellent proposal! I like the idea of having a way to early exit for "undesired" inputs, and keep the main execution path "clean". 👍
joshuahannan
left a comment
There was a problem hiding this comment.
Great addition! I'll definitely want to use this in a lot of places
Work towards #355